﻿using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using HiSport.Application.Auth.Dtos;
using HiSport.Core.Const;
using HiSport.Core.Entity;
using HiSport.Core.Enum;
using HiSport.Core;
using Microsoft.AspNetCore.Http;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Furion.DynamicApiController;

namespace HiSport.Application.Auth
{
    /// <summary>
    /// 授权服务
    /// </summary>
    [ApiDescriptionSettings("系统管理", Tag = "登录授权", SplitCamelCase = false)]
    public class AuthService : ITransient, IAuthService, IDynamicApiController
    {

        public readonly ISqlSugarClient _dbContext;
        public readonly IHttpContextAccessor _httpContextAccessor;
        //private readonly ICaptcha _captcha;

        public AuthService(
            ISqlSugarClient dbContext,
            IHttpContextAccessor httpContextAccessor
            )
        {
            _dbContext = dbContext;
            _httpContextAccessor = httpContextAccessor;
            //_captcha = captcha;
        }

        /// <summary>
        /// 账号密码登录
        /// </summary>
        /// <param name="input"></param>
        /// <remarks>用户名/密码：superadmin/123456</remarks>
        /// <returns></returns>
        public async Task<LoginOutput> Login(LoginInput input)
        {

            // 账号是否存在
            var user = await _dbContext.Queryable<SysUser>().Filter(null, true)
                .FirstAsync(u => u.Account.Equals(input.Account));
            _ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);

            if (user.Password != MD5Encryption.Encrypt(input.Password))
                throw Oops.Oh(ErrorCodeEnum.D1000);

            // 账号是否被冻结
            if (user.Status == StatusEnum.Disable)
                throw Oops.Oh(ErrorCodeEnum.D1017);

            // 租户是否被禁用
            var tenant = await _dbContext.Queryable<SysTenant>().FirstAsync(x => x.Id == user.TenantId);
            if (tenant != null && tenant.Status == StatusEnum.Disable)
                throw Oops.Oh(ErrorCodeEnum.Z1003);
            if (tenant != null && tenant.ExpirationTime.HasValue && tenant.ExpirationTime < DateTime.Now)
                throw Oops.Oh(ErrorCodeEnum.Z1003);


            return await CreateToken(user);
        }

        /// <summary>
        /// 获取登录账号
        /// </summary>
        /// <returns></returns>
        public async Task<LoginUserOutput> GetUserInfo()
        {
            var user = await _dbContext.Queryable<SysUser>().FirstAsync(x => x.Id == CurrentUser.UserId) ?? throw Oops.Oh(ErrorCodeEnum.D1011).StatusCode(401);

            return new LoginUserOutput
            {
                Account = user.Account,
                Avatar = user.Avatar,
                Address = user.Address,
                OrgId = user.OrgId,
                OrgName = null,
            };
        }

        /// <summary>
        /// 退出系统
        /// </summary>
        public void Logout()
        {
            if (string.IsNullOrWhiteSpace(CurrentUser.Account))
                throw Oops.Oh(ErrorCodeEnum.D1011);

            _httpContextAccessor.HttpContext.SignoutToSwagger();
        }



        /// <summary>
        /// 生成Token令牌
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        private async Task<LoginOutput> CreateToken(SysUser user)
        {
            var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object?>
            {
                { ClaimConst.UserId, user.Id },
                { ClaimConst.TenantId, user.TenantId },
                { ClaimConst.Account, user.Account },
                { ClaimConst.AccountType, user.AccountType },
                { ClaimConst.OrgId, user.OrgId },
            }, 300);

            // 生成刷新Token令牌
            var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, 300);

            // 设置响应报文头
            _httpContextAccessor.HttpContext.SetTokensOfResponseHeaders(accessToken, refreshToken);

            return new LoginOutput
            {
                AccessToken = accessToken,
                RefreshToken = refreshToken
            };
        }
    }

}
